using System;
using System.Collections.Generic;
using System.Linq;

using EMan.Common.EnterpriseStructure;

using TrueCode.Core;
using TrueCode.Core.EditableEntity;

namespace EMan.BL.EnterpriseStructure
{
  public static class ChangesetManager
  {
    public static Changeset< T > MakeChangeset< TEditable, T >( IEnumerable< TEditable > editables ) 
      where T : IEntity< T >
      where TEditable : IEditableEntity< T  >
    {
      var added = new List< T >();
      var modified = new List< T >();
      var deleted = new List< int >();

      foreach( var editable in editables )
      {
        switch( editable.State )
        {
          case EditableObjectState.New:
            added.Add( editable.Entity );
            break;
          case EditableObjectState.Modified:
            modified.Add( editable.Entity );
            break;
          case EditableObjectState.Deleted:
            deleted.Add( editable.Entity.Id );
            break;
          case EditableObjectState.Original:
            break;
          default:
            throw new ArgumentOutOfRangeException();
        }
      }

      return new Changeset< T >( added.Count > 0 ? ( IEnumerable< T > )added : EmptyArray< T >.Instance,
                                 modified.Count > 0 ? ( IEnumerable< T > )modified : EmptyArray< T >.Instance,
                                 deleted.Count > 0 ? ( IEnumerable< int > )deleted : EmptyArray< int >.Instance );
    }

    public static void Merge< TEditable, T >( Changeset< T > changeset, ICollection< TEditable > editables ) where T : IEntity< T >
      where TEditable : IEditableEntity< T  >
    {
      foreach( var entity in changeset.Added )
      {
        var editable = editables.Single( e => e.Entity.Key == entity.Key );
        editable.UpdateAll( entity );
        editable.AcceptChanges();
      }

      foreach( var entity in changeset.Modified )
      {
        var editable = editables.Single( e => e.Entity.Key == entity.Key );
        editable.UpdateAll(  entity );
        editable.AcceptChanges();
      }

      var toDelete = changeset.Deleted.Select( id => editables.Single( e => e.Entity.Id == id ) ).ToArray();
      foreach( var editableToDelete in toDelete )
        editables.Remove( editableToDelete );
    }
  }
}